/* 
 * 文 件 名 : HttpHelper.java
 * CopyRright (c) since 2013: 
 * 文件编号： 
 * 创 建 人：Liu Hengyang Email:yangyang8599@163.com QQ:119316891
 * 日    期： 2013-6-21
 * 修 改 人： 
 * 日   期： 
 * 描   述： 
 * 版 本 号： 1.0
 */

package cn.remex.core.net;

import cn.remex.RemexConstants;
import cn.remex.core.exception.NetException;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.exception.StringHandleException;
import cn.remex.core.util.*;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.function.Consumer;

import static cn.remex.core.net.HttpHelper.HttpMethod.GET;
import static cn.remex.core.net.HttpHelper.HttpMethod.POST;
import static cn.remex.core.util.Judgment.nullOrBlank;

/**
 * @author Hengyang Liu yangyang8599@163.com
 * @since 2013-6-21
 */
public final class HttpHelper {
    public enum HttpMethod{
        GET, POST,
    }
    //请求Header Accept
    public static final String HTTP_HEADER_ACCEPT = "Accept";
    //请求Body内容MD5 Header
    public static final String HTTP_HEADER_CONTENT_MD5 = "Content-MD5";
    //请求Header Content-Type
    public static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
    //请求Header UserAgent
    public static final String HTTP_HEADER_USER_AGENT = "User-Agent";
    //请求Header Date
    public static final String HTTP_HEADER_DATE = "Date";

    public static String send(String url) {
        return send(POST, url, null, null, null);
    }
    public static String send(String url, String requestBody) {
        return send(POST, url, requestBody, null, null);
    }
    public static String send(HttpMethod httpMethod, String url) {
        return send(httpMethod, url, null);
    }
    public static String send(HttpMethod httpMethod, String url, String requestBody) {
        return send(httpMethod, url, requestBody, null, null);
    }
    public static String send(HttpMethod httpMethod, String url, String requestBody
            , Consumer<HttpURLConnection> httpConnectionConsumer) {
        return send(httpMethod,url,requestBody,httpConnectionConsumer,null);
    }
    public static String send(HttpMethod httpMethod, String url, String requestBody
            , Consumer<HttpURLConnection> httpConnectionConsumer
            , Consumer<HttpConsumerEntity> httpEntityConsumer) {
        Param<String> param = new Param<>();
        doHttpSend(url, "UTF-8", httpMethod.toString(), null
                , httpConnectionConsumer
                , !nullOrBlank(httpEntityConsumer) ? httpEntityConsumer : innerHttpEntityConsumer -> {
                    try {
                        if(POST==httpMethod)StringHelper.writeToStream(requestBody, "UTF-8", innerHttpEntityConsumer.getOutputStream());
                        param.param = StringHelper.readFromStream("UTF-8", innerHttpEntityConsumer.getInputStream());
                    } catch (Exception e) {
                        throw new NetException(ServiceCode.FAIL, "HttpPost失败，url为：" + url, e);
                    }
                }
        );
        return param.param;
    }

    public static void send(String url,  Consumer<HttpConsumerEntity> httpCosumerEntityConsumer) {
        Assert.notNull(httpCosumerEntityConsumer, ServiceCode.ERROR, "http请求消费不能为空！");
        doHttpSend(url, "UTF-8", null, null, null, httpCosumerEntityConsumer);
    }

//    public static File sendReturnFile(String url, String requestBody, String filePath) {
//        Assert.notNull(filePath, ServiceCode.ERROR, "http请求保存的文件路径不能为空！");
//        Param<File> param = new Param<>();
//        doHttpSend(url, "UTF-8", null, null, null, (httpConsumerEntity) -> {
//            StringHelper.writeToStream(requestBody, "UTF-8", httpConsumerEntity.getOutputStream());
//            param.param = FileHelper.saveFile(filePath, httpConsumerEntity.getInputStream());
//        });
//        return param.param;
//    }


    public static String obtainHttpPack(InputStream input) {
        byte[] buffer = new byte[1024]; // 数据缓冲区
        int count = 0; // 每个缓冲区的实际数据长度
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 请求数据存放对象
        try {
            BufferedInputStream bfInput = new BufferedInputStream(input);
            while ((count = bfInput.read(buffer)) != -1) {
                baos.write(buffer, 0, count);
            }
        } catch (IOException e) {
            throw new NetException(ServiceCode.FAIL, "从HttpServletRequest中读取流异常！", e);
        }
        try {
//			// 得到一个byte数组,提供给平台
            String content = baos.toString("UTF-8");
            return content;
        } catch (UnsupportedEncodingException e) {
            throw new StringHandleException(ServiceCode.FAIL, "读取Post请求报文时，进行UTF-8转码发生异常!", e);
        }
    }

    public static void writeToResponse(String content, HttpServletResponse response) {
        response.setContentType("text/html");
        response.setCharacterEncoding("UTF-8");
        ByteArrayInputStream in = null;
        OutputStream outp = null;
        try {
            in = new ByteArrayInputStream(content.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new StringHandleException(ServiceCode.FAIL, "字符编码不受支持", e);
        }
        writeToResponse(in, response);
    }

    public static void writeToResponse(File file, HttpServletResponse response) {
        FileInputStream in = null;
        OutputStream outp = null;
        try {
            in = new FileInputStream(file);
            writeToResponse(in, response);
        } catch (FileNotFoundException e) {
            RemexConstants.logger.warn("writeToResponse时，无法打开文件 {}", e);
        }
    }

    public static void writeToResponse(InputStream in, HttpServletResponse response) {
        OutputStream outp = null;
        try {
            outp = response.getOutputStream();
            byte[] b = new byte[1024];
            int i;
            while ((i = in.read(b)) > 0) {
                outp.write(b, 0, i);
            }
            outp.flush();
        } catch (FileNotFoundException e) {
            RemexConstants.logger.warn("writeToResponse时，无法打开文件{}", e);
        } catch (IOException e) {
            RemexConstants.logger.warn("writeToResponse时，读取文件失败{}", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {
                    RemexConstants.logger.warn("writeToResponse流关闭失败");
                }
            }
            if (outp != null) {
                try {
                    outp.close();
                    outp = null;
                } catch (IOException e) {
                    RemexConstants.logger.warn("writeToResponse流关闭失败");
                }
            }
        }
    }


    private static void doHttpSend(String url, String charset, String httpMethod, String contextType
            , Consumer<HttpURLConnection> httpConnectionConsumer
            , Consumer<HttpConsumerEntity> httpEntityConsumer) {

//        Assert.notNull(requestBody, ServiceCode.ERROR, "发送的xml报文内容不能为Null！");
        HttpURLConnection httpConnection = null;
        HttpConsumerEntity httpConsumerEntity;
        try {
            // 建立一个HttpURLConnection
            httpConnection = (HttpURLConnection) new URL(url).openConnection();
//            httpConnection.setRequestMethod(nullOrBlank(httpMethod) ? "POST" : httpMethod);
//            httpConnection.setRequestProperty("Content-Type", nullOrBlank(contextType) ? "text/html" : contextType);
//            httpConnection.setRequestProperty("Accept-Charset", nullOrBlank(charset) ? "UTF-8" : charset);
            if(null!=httpConnectionConsumer)httpConnectionConsumer.accept(httpConnection);

            httpConnection.setDoOutput(true);
            httpConnection.setDoInput(true);
//            httpConnection.setAllowUserInteraction(true);
            httpConnection.connect();
            httpConsumerEntity = new HttpConsumerEntity(httpConnection);
            if(null!=httpEntityConsumer)httpEntityConsumer.accept(httpConsumerEntity);

        } catch (Exception e) {
            throw new NetException(ServiceCode.FAIL, "HttpPost失败，url为：" + url, e);
        } finally {
            if (httpConnection != null) {
                httpConnection.disconnect();//此处内部关闭in out 流
            }
        }
    }
}

